//Copyright (c) 2012 The cwkshell Authors. All rights reserved. 
// Use of this source code is governed by a BSD-style license that can be 
// found in the LICENSE file. 
#include "cuc/src/cwkshell/browser/url_request_shell_job.h" 


#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/debug/trace_event.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "base/memory/ref_counted_memory.h"
#include "cuc/src/cwkshell/browser/webui/shell_webui_data_manager.h" 
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/base/net_errors.h"

namespace cuc{ 
	namespace shell{ 


		URLRequestShellJob::URLRequestShellJob(net::URLRequest* request,
			net::NetworkDelegate* network_delegate,
			ShellWebUIDataManager* shell_webui_data_manager)
			: net::URLRequestJob(request, network_delegate),
			data_offset_(0),
			pending_buf_size_(0),
			allow_caching_(true),
			shell_webui_data_manager_(shell_webui_data_manager),
			ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {

				DCHECK(shell_webui_data_manager_);

				LOG(INFO)<<"URLRequestShellJob::URLRequestShellJob() ";
		}

		URLRequestShellJob::~URLRequestShellJob() {
			CHECK(!shell_webui_data_manager_->HasPendingJob(this));
		}

		void URLRequestShellJob::GetResponseInfo( net::HttpResponseInfo* info ) 
		{
			DCHECK(!info->headers);
			// Set the headers so that requests serviced by ChromeURLDataManager return a
			// status code of 200. Without this they return a 0, which makes the status
			// indistiguishable from other error types. Instant relies on getting a 200.
			info->headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
			info->headers->AddHeader("Cache-Control: no-cache");
		}

		bool URLRequestShellJob::GetMimeType( std::string* mime_type ) const 
		{
			*mime_type = mime_type_;
			return !mime_type_.empty();
		}

		void URLRequestShellJob::Start() 
		{
			// Start reading asynchronously so that all error reporting and data
			// callbacks happen as they would for network requests.
			MessageLoop::current()->PostTask(
				FROM_HERE,
				base::Bind(&URLRequestShellJob::StartAsync,
				weak_factory_.GetWeakPtr()));

			TRACE_EVENT_ASYNC_BEGIN1("browser", "DataManager:Request", this, "URL",
				request_->url().possibly_invalid_spec());

		}

		void URLRequestShellJob::Kill() {
			shell_webui_data_manager_->RemoveRequest(this);
		}

		void URLRequestShellJob::MimeTypeAvailable(const std::string& mime_type) {
			set_mime_type(mime_type);
			NotifyHeadersComplete();
		}

		void URLRequestShellJob::DataAvailable(base::RefCountedMemory* bytes) {
			TRACE_EVENT_ASYNC_END0("browser", "DataManager:Request", this);
			if (bytes) {
				// The request completed, and we have all the data.
				// Clear any IO pending status.
				SetStatus(net::URLRequestStatus());

				data_ = bytes;
				int bytes_read;
				if (pending_buf_.get()) {
					CHECK(pending_buf_->data());
					CompleteRead(pending_buf_, pending_buf_size_, &bytes_read);
					pending_buf_ = NULL;
					NotifyReadComplete(bytes_read);
				}
			} else {
				// The request failed.
				NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
					net::ERR_FAILED));
			}
		}


		bool URLRequestShellJob::ReadRawData(net::IOBuffer* buf, int buf_size,
			int* bytes_read) {
				if (!data_.get()) {
					SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
					DCHECK(!pending_buf_.get());
					CHECK(buf->data());
					pending_buf_ = buf;
					pending_buf_size_ = buf_size;
					return false;  // Tell the caller we're still waiting for data.
				}

				// Otherwise, the data is available.
				CompleteRead(buf, buf_size, bytes_read);
				return true;
		}

		void URLRequestShellJob::CompleteRead(net::IOBuffer* buf, int buf_size,
			int* bytes_read) {
				int remaining = static_cast<int>(data_->size()) - data_offset_;
				if (buf_size > remaining)
					buf_size = remaining;
				if (buf_size > 0) {
					memcpy(buf->data(), data_->front() + data_offset_, buf_size);
					data_offset_ += buf_size;
				}
				*bytes_read = buf_size;
		}

		void URLRequestShellJob::StartAsync() {
			if (!request_)
				return;
			LOG(INFO)<<" URLRequestShellJob::StartAsync() :the url is :"<<request_->url().spec();

			if (!shell_webui_data_manager_->StartRequest(request_->url(), this)) {
				NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
					net::ERR_INVALID_URL));
			}
		}


	} //namespace shell 
} //namespace cuc 
